////////////////////////////////////////////////////////////////////////////////

#ifndef _SERVER_H_
#include "server.h"
#endif

////////////////////////////////////////////////////////////////////////////////

#ifndef _TIMER_H_
#include "timer.h"
#endif

#ifndef _SERVERSTATEPACKET_H_
#include "serverstatepacket.h"
#endif

#ifndef _SERVERINFOPACKET_H_
#include "serverinfopacket.h"
#endif

#ifndef _SERVEREVENTPACKET_H_
#include "servereventpacket.h"
#endif

////////////////////////////////////////////////////////////////////////////////

Server* Server::m_Instance = NULL;

////////////////////////////////////////////////////////////////////////////////

Server::Server()
{
}


////////////////////////////////////////////////////////////////////////////////


Server::~Server()
{
}


////////////////////////////////////////////////////////////////////////////////


void Server::Start(const std::string& _mapName)
{
    // Run game
    LoadMap(_mapName);
    RunGameLoop();
}


////////////////////////////////////////////////////////////////////////////////


void Server::RunGameLoop()
{
    while ( true )
    {
        ProcessLogic();
        NotifyClients();
        Sleep();
    }
}


////////////////////////////////////////////////////////////////////////////////


void Server::ProcessLogic()
{
    // Logic is processed in engine
    m_Engine.UpdateState();
}


////////////////////////////////////////////////////////////////////////////////


void Server::NotifyClients()
{
    if ( IsItTimeToSendAState() )
    {
        SendStateToAllClients( m_Engine.GetState() );
    }
}


////////////////////////////////////////////////////////////////////////////////


void Server::NotifyAboutKilling( int _playerID, int _killerID )
{
    ServerEventPacket event(_playerID, _killerID );
    SendEventToAllClients(event);
}


////////////////////////////////////////////////////////////////////////////////


void Server::Sleep()
{
    Timer::Sleep(1);
}


////////////////////////////////////////////////////////////////////////////////


bool Server::IsItTimeToSendAState() const
{
    // Send a packet every 30 ms
    const size_t sendDelay = 30;

    static size_t prevTime = Timer::GetCurrTime();
    size_t currTime = Timer::GetCurrTime();

    if (prevTime + sendDelay < currTime)
    {
        prevTime = currTime;
        return true;
    }
    else
        return false;
}


////////////////////////////////////////////////////////////////////////////////


void Server::SendStateToAllClients( const ServerState& _state )
{
    // Clean deleted connections
    m_Network.DeleteObsoleteConnections();

    // Get all clients IDs
    const IntSet& clientIDs = m_Engine.GetClientsIDs();

    // Compose server state packet
    ServerStatePacket serverStatePacket(Timer::GetCurrTime(), _state);

    // Send packet to each client
    for ( IntSet::const_iterator it = clientIDs.begin(); it != clientIDs.end(); ++it )
        m_Network.SendServerState(*it, serverStatePacket);
}


////////////////////////////////////////////////////////////////////////////////


void Server::SendEventToAllClients( const ServerEventPacket& _event )
{
    // Clean deleted connections
    m_Network.DeleteObsoleteConnections();

    // Get all clients IDs
    const IntSet& clientIDs = m_Engine.GetClientsIDs();

    // Send packet to each client
    for ( IntSet::const_iterator it = clientIDs.begin(); it != clientIDs.end(); ++it )
        m_Network.SendServerInfo(*it, _event);
}


////////////////////////////////////////////////////////////////////////////////


Server& Server::Instance()
{
    if (!m_Instance)
        m_Instance = new Server;

    return *m_Instance;
}


////////////////////////////////////////////////////////////////////////////////


ServerNetwork& Server::Network()
{
    return m_Network;
}


////////////////////////////////////////////////////////////////////////////////


ServerEngine& Server::Engine()
{
    return m_Engine;
}


////////////////////////////////////////////////////////////////////////////////


ServerBattlefield& Server::Battlefield()
{
    return m_Engine.Battlefield();
}


////////////////////////////////////////////////////////////////////////////////


void Server::LoadMap(const std::string& _mapName)
{
    m_Engine.LoadMap(_mapName);
}


////////////////////////////////////////////////////////////////////////////////
